package de.recipeminer.tools;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import de.recipeminer.environments.ExecutionContextProvider;
import org.apache.log4j.Logger;
import org.jruby.CompatVersion;
import org.jruby.embed.InvokeFailedException;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.ScriptingContainer;

import java.io.File;
import java.io.InputStream;
import java.util.List;


public class RubyScriptContainerProvider {
    public static Logger logger = Logger.getLogger(RubyScriptContainerProvider.class);
    private static ScriptingContainer defaultInstance = null;
    private final static String JAR_PROBING_STRING = "META-INF/jruby.home/lib/ruby/1.9";
    private final static String JAR_LOCATION_RUBY = "src/main/ruby";

    
    /**
     * Returns Ruby Runtime Container which is persistent over the complete program
     * execution. It remembers loaded files and changed global variables. Local variables
     * passed to this container persist across multiple evaulation commands.
     *
     * @return the default scripting container
     */
    public static ScriptingContainer getDefaultContainer() {
        if (defaultInstance == null) {

            defaultInstance = new ScriptingContainer(LocalContextScope.THREADSAFE,
                    LocalVariableBehavior.PERSISTENT);
            initDefaultContainer();
        }
        return defaultInstance;
    }

    /**
     * Creates a transient scripting container unaware of modifications in the default
     * container. This container does not persist local variables passed to it accross
     * different evaluations and will be subject to garbage-collection.
     *
     * @return a temporary scripting container
     */
    public static ScriptingContainer getTransientContainer() {
        ScriptingContainer container = new ScriptingContainer(LocalContextScope.SINGLETHREAD,
                LocalVariableBehavior.TRANSIENT);
        container.setCompatVersion(CompatVersion.RUBY1_9);
        return container;
    }

    private static void initDefaultContainer() {
        defaultInstance = new ScriptingContainer(LocalContextScope.THREADSAFE,
                LocalVariableBehavior.PERSISTENT);
        //RubyInstanceConfig defaultInstanceConfig = defaultInstance.getProvider().getRubyInstanceConfig();
        defaultInstance.setCompatVersion(CompatVersion.RUBY1_9);
        List<String> loadPaths = Lists.newLinkedList();
        if ( ! Tools.executedFromJar()) {
            // wer are in the Maven build environment - use maven.properties to find the ruby source paths
            loadPaths.add(Tools.getRubySourcePath());
            loadPaths.add(Tools.getRubyTestSourcePath());
        }
        String home = defaultInstance.getHomeDirectory();
        if (home != null) {
            String binPath = Joiner.on(File.separator).join(home, "bin");
            loadPaths.add(binPath);
        }
        defaultInstance.getLoadPaths().addAll(0, loadPaths);
        defaultInstance.getProvider().getRubyInstanceConfig().setScriptFileName("<JRubyEmbedScript>");
        try {
            defaultInstance.runScriptlet("puts 'loadpath:'\nputs $:");
            defaultInstance.put("JAR_PROBING_STRING", JAR_PROBING_STRING);
            defaultInstance.put("JAR_LOCATION_RUBY", JAR_LOCATION_RUBY);
            InputStream stream = ExecutionContextProvider.currentResourceFinder().getStream("add_ruby_src_in_jar.rb");
            defaultInstance.runScriptlet(stream, "add_ruby_src_in_jar.rb");
            defaultInstance.runScriptlet("require 'main/init'");
        } catch (InvokeFailedException ife) {
            logger.error("Error loading init script", ife);
            throw ife;
        }
    }

    private static String searchAndReplaceLoadpathEntry(String searchSuffix, String replaceSuffix) {
        logger.debug("checking for suffix" + searchSuffix);
        for(String entry : defaultInstance.getLoadPaths()) {
            logger.debug("checking: |start|" + entry + "|end|");

            if(entry.endsWith(searchSuffix)) {
                return entry.replace(searchSuffix, replaceSuffix);
            }
        }
        return null;
    }
}
